﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;//引用命名空间
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Collections;

using ctdFunction;
using JsRunTool;

namespace ctdReader
{
    public class CardReaderInterface:Function
    {	
	    /************************************************************************/
	    /* 打开读卡器
	    /*
	    /* return: 0- ok, other- false
	    /************************************************************************/
        public virtual int openReader()
        {
            return 10;
        }
	
	    /************************************************************************/
	    /* 关闭读卡器
	    /*
	    /* return: 0- ok, other- false
	    /************************************************************************/
        public virtual int closeReader()
        {
            return 10;
        }

	    /************************************************************************/
	    /* 对卡片进行上电复位。
	    /*
	    /* return: 0- ok, other- false
	    /************************************************************************/
        public virtual int cardReset()
        {
            return 10;
        }

	    /************************************************************************/
        /* 对卡片进行下电                                                         
        /************************************************************************/
        public virtual int cardDown()
        {
            return 10;
        }
	
	    /************************************************************************/
	    /* 向卡发送APDU数据，getResp 取得返回数据，getReaderStatus 取得返回状态
	    /*
	       apdu  : APDU命令，字符串格式
	    /* return: SW1SW2
	    /************************************************************************/
	    public virtual long sendApdu(string apdu)
        {
            return 10;
        }
	    /************************************************************************/
	    /* 取得APDU命令的返回状态
	    /*
	       sw    : 存放返回状态的字符串，如“9000”
	    /* return: sw 的长度
	    /************************************************************************/
//	    public virtual int getSw1Sw2(char[] sw);
        public virtual string getSw1Sw2()
        {
            return "";
        }
	    /************************************************************************/
	    /* 取得APDU命令的返回数据
	    /*
	       resp  : 存放返回数据的字符串
	    /* return: resp 的长度
	    /************************************************************************/
//	    public virtual int getResp(char[] resp);
        public virtual string getResp()
        {
            return "";
        }
	    /************************************************************************/
	    /* 判断读卡器(和卡片)的状态
	    /*
	    /* return: 0- 卡片正常
	    /************************************************************************/
	    public virtual int getReaderStatus()
        {
            return 10;
        }
	    /************************************************************************/
	    /* 读卡器蜂鸣
	    /************************************************************************/
        public virtual void readerBeep()
        {

        }
    }


    public class D8ReaderTL : CardReaderInterface
    {
        public D8ReaderTL()
        {
            m_ReaderPort = 100;
            m_hReader = IntPtr.Zero;
        }

        [DllImport("dcrf32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
            , EntryPoint = "dc_init", SetLastError = false)]
        public static extern IntPtr dc_init(int port, int baud);

        [DllImport("dcrf32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
            , EntryPoint = "dc_reset", SetLastError = false)]
        public static extern int dc_reset(IntPtr href, int baud);

        [DllImport("dcrf32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
            , EntryPoint = "dc_card_hex", SetLastError = false)]
        public static extern int dc_card_hex(IntPtr href, char mode, StringBuilder RespBuf);

        [DllImport("dcrf32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "dc_pro_reset_hex", SetLastError = false)]
        public static extern int dc_pro_reset_hex(IntPtr href, ref byte len, StringBuilder RespBuf);

        [DllImport("dcrf32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "dc_pro_commandlinkEXT_hex", SetLastError = false)]
        public static extern int dc_pro_commandlinkEXT_hex(IntPtr href, int lenApdu, string apdu, ref byte len, StringBuilder RespBuf,char tt,char FG);

        [DllImport("dcrf32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
          , EntryPoint = "dc_beep", SetLastError = false)]
        public static extern int dc_beep(IntPtr href, int _Msec);


        public override int openReader() 
        {
            m_hReader = dc_init(m_ReaderPort, 115200);

            if (m_hReader == IntPtr.Zero || m_hReader.ToInt32() == -1)
            {
                return -1;
            }
            //dc_beep(m_hReader,10);
            return 0;
        }

        public override int cardReset()
        {
            m_RespBuf ="";
            m_SW = "0000";

            int ret = dc_reset(m_hReader, 1);
            if (ret != 0) {
                return ret;
            }

            StringBuilder strSnr = new StringBuilder(50);
            ret = dc_card_hex(m_hReader, '0', strSnr);
            if (ret != 0) {
                return ret;
            }
            m_snr = strSnr.ToString();

            StringBuilder sbdAts = new StringBuilder(50);
            byte strLen = 0;
            ret = dc_pro_reset_hex(m_hReader, ref strLen, sbdAts);
            if (ret != 0) {
                return ret;
            }
            m_RespBuf = sbdAts.ToString();
            m_SW = "9000";

            return 0;
        }

        public override long sendApdu(string apdu)
        {
            m_RespBuf = "";
            m_SW = "0000";

            byte rLen = 0;
            StringBuilder tmp = new StringBuilder(500);
            int ret = dc_pro_commandlinkEXT_hex(m_hReader, apdu.Length / 2, apdu, ref rLen, tmp, '\x07', '\x40');
            if (ret != 0 ) {
                return ret;
            }
            m_RespBuf = tmp.ToString().Substring(0, tmp.Length - 4);
            m_SW = tmp.ToString().Substring(tmp.Length - 4);

            return strToToLong(m_SW);
        }

        public override string getSw1Sw2()
        {
            return m_SW;
        }

        public override string getResp()
        {
            return m_RespBuf;
        }

        public override int getReaderStatus()
        {
            if (m_hReader == IntPtr.Zero) {
                return -1;
            }

            return cardReset();
        }

        public string getSnr()
        {
            return m_snr;
        }

        public string getSna()
        {
            return m_snr.Substring(6, 2) + m_snr.Substring(4, 2) + m_snr.Substring(2, 2) + m_snr.Substring(0, 2);
        }

        public override void readerBeep()
        {
            dc_beep(m_hReader,10);
        }

        public void setPort(int port)
        {
            m_ReaderPort = port;
        }
        protected IntPtr m_hReader;
        protected int m_ReaderPort;
        protected string m_SW;
        protected string m_RespBuf;
        protected string m_snr;

    }

    public class D6Reader : CardReaderInterface
    {
        [DllImport("dcic32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "IC_Status", SetLastError = false)]
        public static extern int IC_Status(IntPtr href);

        [DllImport("dcic32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
        , EntryPoint = "IC_InitComm_Baud", SetLastError = false)]
        public static extern IntPtr IC_InitComm_Baud(int port, int combaud);

        [DllImport("dcic32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
            , EntryPoint = "IC_InitType", SetLastError = false)]
        public static extern int IC_InitType(IntPtr href, int type);

        [DllImport("dcic32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
            , EntryPoint = "IC_CpuReset_Hex", SetLastError = false)]
        public static extern int IC_CpuReset_Hex(IntPtr href, ref byte len, StringBuilder RespBuf);

        [DllImport("dcic32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "IC_CpuApduEXT_Hex", SetLastError = false)]
        public static extern int IC_CpuApduEXT_Hex(IntPtr href, int lenApdu, string apdu,ref byte len, StringBuilder RespBuf);

        [DllImport("dcic32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "IC_DevBeep", SetLastError = false)]
        public static extern int IC_DevBeep(IntPtr href, char beeptime);

        public D6Reader()
        {
            m_hReader = IntPtr.Zero;
            m_ReaderPort = 100;
        }

        public D6Reader(int readerPort)
        {
            m_ReaderPort = readerPort;
            m_hReader = IntPtr.Zero;
        }

        public void setReader(IntPtr id)
        {
            m_hReader = id;
        }

        public IntPtr getReader()
        {
            return m_hReader;
        }

        public override int openReader()
        {
            m_hReader = IC_InitComm_Baud(m_ReaderPort, 115200);
            if (m_hReader == IntPtr.Zero || m_hReader.ToInt32() == -1)
            {
                return -1;
            }
            int ret = IC_InitType(m_hReader, 0x0C);
            if (ret != 0)
            {
                return -2;
            }
            readerBeep();
            return 0;
        }

        public override int cardReset()
        {
            m_RespBuf = "";
            m_SW = "0000";

            byte strLen = 0;
            StringBuilder sBdAtr= new StringBuilder(50);
            int ret = IC_CpuReset_Hex(m_hReader, ref strLen, sBdAtr);
            if (ret != 0)
            {
                m_RespBuf = "d6复位失败!";
                return -1;
            }

            m_RespBuf = sBdAtr.ToString();
            m_SW = "9000";
            return ret;
        }

        public override long sendApdu(string apdu)
        {
            m_RespBuf = "";
            m_SW = "0000";

            byte rLen = 0;
            StringBuilder tmpRsp = new StringBuilder(500);
            if (0 != IC_CpuApduEXT_Hex(m_hReader, apdu.Length / 2, apdu, ref rLen, tmpRsp))
            {
                m_SW = "FD00";
                return 0xFD00;
            }

            m_RespBuf = tmpRsp.ToString().Substring(0, tmpRsp.Length - 4);
            m_SW = tmpRsp.ToString().Substring(tmpRsp.Length - 4);

            return strToToLong(m_SW);
        }

        public override string getSw1Sw2()
        {
            return m_SW;
        }

        public override string getResp()
        {
            return m_RespBuf;
        }

        public override int getReaderStatus()
        {
            if (m_hReader == IntPtr.Zero)
            {
                return -1;
            }

            return IC_Status(m_hReader);
        }

        public override void readerBeep()
        {
            IC_DevBeep(m_hReader, '\t');
        }
        protected IntPtr m_hReader;
        protected int m_ReaderPort;
        protected string m_SW;
        protected string m_RespBuf;
        protected string m_LastApdu;
        // 	    CardDataLog *m_pCardApduLog;
        protected bool m_IsBaudMustDefault;
  //      int m_IS_RESET_PPS;	// 0 提速
    }

    public class PCSCRead : CardReaderInterface
    {
        protected string m_SW;
        protected string m_RespBuf;

        public List<string> m_readerList = new List<string>();
        private string errMsg = "";
        private int runResult = -1;
        //private static IntPtr SCARD_PCI_T0;
        private static IntPtr SCARD_PCI_T1;

        private const int SCARD_SUCCESS = 0;
        /// <summary>
        /// 上下文句柄
        /// </summary>
        private int hContext = 0;
        /// <summary>
        /// 卡片句柄
        /// </summary>
        private int hCard = 0;
        /// <summary>
        /// 卡片使用的传输协议
        /// </summary>
        private int activeProtocol = 0;
        /// <summary>
        /// 使用的读卡器名称
        /// </summary>
        public string ReaderName = "";

        public enum SCARD_SCPOE : int
        {
            USER = 0x00000000,
            TERMAINAL = 0x00000001,
            SYSTEM = 0x00000002
        }

        public class SCARD_IO_REQUEST
        {
            public int dwProtocol;
            public int cbPciLength;
        }

        /// <summary>
        /// 创建读卡器设备管理上下文
        /// </summary>
        /// <param name="dwScope">读卡器可使用范围，SCARD_SCPOE.USER为当前用户,
        /// TERMAINAL未知，SYSTEM为当前系统所有用户</param>
        /// <param name="reserverd1">保留，必须为0</param>
        /// <param name="reserverd2">保留，必须为0</param>
        /// <param name="hContext">传入传出参数，设备管理器句柄</param>
        /// <returns></returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardEstablishContext(UInt32 dwScope
                                                      , int reserverd1
                                                      , int reserverd2
                                                      , out int hContext);

        /// <summary>
        /// 返回读卡设备列表
        /// </summary>
        /// <param name="hContext">设备管理器句柄</param>
        /// <param name="mszGroups">没什么用的参数，送null就好</param>
        /// <param name="mszReaders">设备名称集合</param>
        /// <param name="mszReadersSize">设备名称集合总长度</param>
        /// <returns>如果返回为0，则代表获取读卡设备成功</returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardListReaders(int hContext
                                                , byte[] mszGroups
                                                , byte[] mszReaders
                                                , ref int mszReadersSize);

        /// <summary>
        /// 卡片连接
        /// </summary>
        /// <param name="hContext">设备句柄</param>
        /// <param name="szReader">读卡器名称</param>
        /// <param name="dwShareMode">卡片公用模式</param>
        /// <param name="dwProtocols">协议使用模式</param>
        /// <param name="hCard">卡连接句柄</param>
        /// <param name="activeProtocol">卡运行协议</param>
        /// <returns></returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardConnect(int hContext
                                             , string szReader
                                             , int dwShareMode
                                             , int dwProtocols
                                             , ref int hCard
                                             , ref int activeProtocol);

        /// <summary>
        /// 设置卡片状态
        /// </summary>
        /// <param name="hCard">卡片句柄</param>
        /// <param name="szReaderName">设备名称</param>
        /// <param name="hContent">设备句柄</param>
        /// <param name="pdwState">卡片所处状态</param>
        /// <param name="pdwProtocol">卡片使用的协议</param>
        /// <param name="ATR">ATR字串</param>
        /// <param name="length">ATR字串长度</param>
        /// <returns></returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardStatus(int hCard
                                            , string szReaderName
                                            , ref int hContent
                                            , ref int pdwState
                                            , ref int pdwProtocol
                                            , byte[] ATR
                                            , ref int length);


        /// <summary>
        /// 向卡片发送数据
        /// </summary>
        /// <param name="hCard">卡片句柄</param>
        /// <param name="pioSendPci">指令的协议头结构的指针</param>
        /// <param name="pbSendBuffer">写卡数据</param>
        /// <param name="cbSendLength">写卡数据长度</param>
        /// <param name="pioRecvPci"></param>
        /// <param name="pbRecvBuffer">返回数据</param>
        /// <param name="pcbRecvLength"></param>
        /// <returns></returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardTransmit(
                                 int hCard,
                                 IntPtr pioSendPci,
                                 //ref SCARD_IO_REQUEST pioSendPci,
                                 byte[] pbSendBuffer,
                                 int cbSendLength,
                                 SCARD_IO_REQUEST pioRecvPci,
                                 byte[] pbRecvBuffer,
                                 ref int pcbRecvLength
            );
  

        /// <summary>
        /// 释放连接
        /// </summary>
        /// <param name="hCard">调用SCardConnect获得的引用值</param>
        /// <param name="dwDisposition">
        /// SCARD_LEAVE_CARD = 0;对卡不做任何操作
        /// SCARD_RESET_CARD = 1;卡复位
        /// SCARD_UNPOWER_CARD = 2;对卡断电
        /// SCARD_EJECT_CARD = 3; 弹出卡
        /// </param>
        /// <returns>
        /// </returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardDisconnect(
                                 int hCard,
                                 int dwDisposition
            );

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="hContext">资源句柄</param>
        /// <returns></returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardReleaseContext(
                                 int hContext
            );

        [DllImport("WinSCard.dll")]
        public static extern int SCardBeginTransaction(int hContext);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hCard"></param>
        /// <param name="dwShareMode"></param>
        /// <param name="dwProtocols"></param>
        /// <param name="dwDisposition"></param>
        /// <param name="activeProtocol"></param>
        /// <returns></returns>
        [DllImport("WinSCard.dll")]
        public static extern int SCardReconnect(int hCard,
                                              int dwShareMode
                                             , int dwProtocols
                                             , int dwInitialization
                                             , ref int activeProtocol);

        /// <summary>
        /// 获取读卡器列表
        /// </summary>
        /// <returns></returns>
        #region iniDevice
        public List<string> iniDevice()
        {
            m_readerList.Clear();
            //获取设备上下文句柄
            runResult = SCardEstablishContext(0, 0, 0, out hContext);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取设备上下文失败，错误代码为：" + runResult.ToString("X");

                //  throw new Exception(errMsg);
                return null;
            }

            if (hContext == 0)
            {
                errMsg = "未能获取设备上下文句柄";

                // throw new Exception(errMsg);
                return null;
            }
            int mszReaderSize = 0;
            //获取读卡器列表，第一次用于获取字符串长度
            runResult = SCardListReaders(hContext, null, null, ref mszReaderSize);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");

                //  throw new Exception(errMsg);
                return null;
            }

            List<string> readerList = new List<string>();

            byte[] reads = new byte[mszReaderSize];

            //获取读卡器列表
            runResult = SCardListReaders(hContext, null, reads, ref mszReaderSize);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");
                // throw new Exception(errMsg);
                return null;
            }

            string rName = "";
            int indx = 0;

            // Convert reader buffer to string
            while (reads[indx] != 0)
            {

                while (reads[indx] != 0)
                {
                    rName = rName + (char)reads[indx];
                    indx = indx + 1;
                }

                // Add reader name to list
                readerList.Add(rName);
                m_readerList.Add(rName);
                rName = "";
                indx = indx + 1;

            }

            return readerList;

        }
        #endregion

        public override int openReader()
        {
            
            if (hContext == 0)
            {
                errMsg = "获取设备上下文句柄失败。初始化卡片前需初始化设备！";
                MessageBox.Show(errMsg, "PCSC");
                return -1;
            }
            if (hCard != 0)
            {
                SCardDisconnect(hCard, 2);

            }

            bool isConnectCard = false;
            const int SCARD_PROTOCOL_T0 = 0x01;                 // T=0 is the active protocol.
            const int SCARD_PROTOCOL_T1 = 0x02;                 // T=1 is the active protocol.

            runResult = SCardConnect(hContext, ReaderName, 1, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, ref hCard, ref activeProtocol);

            if (runResult != SCARD_SUCCESS)
            {
                //无卡打开
                runResult = SCardConnect(hContext, ReaderName, 3, 0, ref hCard, ref activeProtocol);
                if (runResult != SCARD_SUCCESS)
                {
                    // MessageBox.Show("读卡器打开失败！", "PCSC", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                    MessageBox.Show("读卡器打开失败！", "PCSC");
                    //   errMsg = "读卡器打开失败";
                    // throw new ScriptException(1, 1, 1, errMsg);
                    return -1;


                }
                //  MessageBox.Show("未检测到卡,PCSC读卡器要插卡打工！", "PCSC");
                isConnectCard = true;


            }
            else
            {

                isConnectCard = true;

            }
            return 0;
        }

        public override int cardReset()
        {
            int readerLength = 0;

            int cardStatus = 0;

            int cardProtocal = 0;

            int atrLength = 0;
            const int SCARD_PROTOCOL_T0 = 0x01;                 // T=0 is the active protocol.
            const int SCARD_PROTOCOL_T1 = 0x02;                 // T=1 is the active protocol.

            runResult = SCardReconnect(hCard, 2, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, 2, ref activeProtocol);
            if (runResult != SCARD_SUCCESS)
            {
                return -1;
            }

            runResult = SCardStatus(hCard, ReaderName, ref readerLength
                                            , ref cardStatus, ref cardProtocal, null, ref atrLength);

            if (runResult != SCARD_SUCCESS)
            {
                return -1;
            }

            if (cardStatus != 6)
            {
                return -1;
                //  errMsg = "复位失败";

                //  throw new ScriptException(1, 1, 1, errMsg);
            }

            byte[] ATR = new byte[atrLength];

            runResult = SCardStatus(hCard, ReaderName, ref readerLength
                                            , ref cardStatus, ref cardProtocal, ATR, ref atrLength);

            if (runResult != SCARD_SUCCESS)
            {
                return -1;
                // errMsg = "复位失败";
                //  throw new ScriptException(1, 1, 1, errMsg);

            }
            else
            {
                m_RespBuf = ByteToHexStr(ATR);
                m_SW = "9000";
            }
            return 0;

        }

        public override long sendApdu(string apdu)
        {
            byte[] sendMessageBuffer = StringToByteSequence(apdu);

            byte[] receiveMessageByte = new byte[256];
            int receiveLength = 256;
            SCARD_IO_REQUEST IO_Request = new SCARD_IO_REQUEST();
            IO_Request.dwProtocol = 0;
            IO_Request.cbPciLength = 8;
            runResult = SCardTransmit(hCard
                                            , SCARD_PCI_T1
                                            , sendMessageBuffer
                                            , sendMessageBuffer.Length
                                            , null, receiveMessageByte, ref receiveLength);
//             runResult = SCardTransmit(hCard
//                                 , ref IO_Request
//                                 , sendMessageBuffer
//                                 , sendMessageBuffer.Length
//                                 , null, receiveMessageByte, ref receiveLength);

            if (runResult != SCARD_SUCCESS)
            {
                m_SW = "FD00";
                throw new Exception("发送指令失败!");
            }
            m_RespBuf = ByteToHexStr(receiveMessageByte).Substring(0, receiveLength * 2);

            if (receiveLength == 2)
            {
                m_SW = m_RespBuf.Substring(0, 4);
                m_RespBuf = "";
                return Function.strToToLong(m_SW);
            }
            m_SW = m_RespBuf.Substring(receiveLength * 2 - 4);

            m_RespBuf = m_RespBuf.Substring(0, receiveLength * 2 - 4);
            return Function.strToToLong(m_SW);
        }

        public override string getSw1Sw2()
        {
            return m_SW;
        }

        public override string getResp()
        {
            return m_RespBuf;
        }

        public override int getReaderStatus()
        {
            if (hCard == 0)
            {
                return -1;
            }

            int readerLength = 0;

            int cardStatus = 0;

            int cardProtocal = 0;

            int atrLength = 0;
            const int SCARD_PROTOCOL_T0 = 0x01;                 // T=0 is the active protocol.
            const int SCARD_PROTOCOL_T1 = 0x02;                 // T=1 is the active protocol.



            runResult = SCardReconnect(hCard, 2, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, 2, ref activeProtocol);
            if (runResult != SCARD_SUCCESS)
            {
                return -1;
            }

            runResult = SCardStatus(hCard, ReaderName, ref readerLength
                                            , ref cardStatus, ref cardProtocal, null, ref atrLength);

            if (runResult != SCARD_SUCCESS)
            {
                return -1;
            }
            return 0;
        }


        public static byte[] StringToByteSequence(string sourceString)
        {
            int i = 0, n = 0;
            int j = (sourceString.Length) / 2;

            byte[] a = new byte[j];
            for (i = 0, n = 0; n < j; i += 2, n++)
            {
                a[n] = Convert.ToByte(sourceString.Substring(i, 2), 16);
            }
            return a;
        }

        public override int cardDown()
        {
            return SCardDisconnect(hCard, 2);
        }
    }

    public class MyCommand : Function
    {
        public static int ID_CARD_READER = 2;
        public static int ID_KEY_HOST = 1;

        protected CardDataLog m_Log;
        protected CardReaderInterface  pCardReader;
        protected bool isAutoGetResp;

        protected string m_LastApdu;
        public int m_StationId;
        public int deviceId;                           // 外部设备ID，读卡器、加密机


        public MyCommand()
        {
            isAutoGetResp = false;
            m_Log = new CardDataLog(1);
        }

        ~MyCommand()
        {
            m_Log.closeLogFile();
        }

        public void autogetresp(int mode)
        {
            if (mode == 0)
            {
                isAutoGetResp = false;
            }
            else
            {
                isAutoGetResp = true;
            }
        }

        public void setCardReader(ref CardReaderInterface reader)
        {
            pCardReader = reader;
            setreader(2);
            autogetresp(1);
        }

        CardReaderInterface getCardReader() {
            return pCardReader;
        }

        public void setStationId(int id)
	    {
		    m_StationId = id;
	    }

        public int getStationId()
	    {
		    return m_StationId;
	    }

        public void openreader()
        {
            if (deviceId == ID_CARD_READER)
            {
                if (pCardReader.getReaderStatus() != 0)
                {
                    int result = pCardReader.openReader();

                    if (0 != result)
                    {
                        throw new ScriptException(1,1,1,"打开读卡器失败!"); 
                    }
                }
            }
        }
        public void sendcmd(string cmdStr)
        {
            m_LastApdu = cmdStr;
            if (deviceId == ID_CARD_READER)
            {
                if (cmdStr.Length > 10)
                {
                    byte[] b = strToToHexByte(cmdStr);
                    int len = b[4];
                    if (len * 2 + 10 != cmdStr.Length)
                    {
                        m_Log.setTransmitApdu(cmdStr, ":err: APDU P3 ERROR !");
                        throw new ScriptException(getStationId(), 1, 0,cmdStr + ":err: APDU P3 ERROR !");
                    }
                }

                long sw = pCardReader.sendApdu(cmdStr);
                m_Log.setTransmitApdu(cmdStr, pCardReader.getResp() + pCardReader.getSw1Sw2());

		        long sw1 = sw & 0xff00;

		        if((isAutoGetResp == true) && (sw1 == 0x6100 || sw1 == 0x9f00)) {

                    string swStr = pCardReader.getSw1Sw2();
                    string p3 = swStr.Substring(2);

			        if((sw1) == 0x9f00) {
				        pCardReader.sendApdu("A0C00000" + p3);
                        m_Log.setTransmitApdu("A0C00000" + p3, pCardReader.getResp() + pCardReader.getSw1Sw2());

			        } else {
				        pCardReader.sendApdu("00C00000" + p3);
                        m_Log.setTransmitApdu("00C00000" + p3, pCardReader.getResp() + pCardReader.getSw1Sw2());
			        }
		        }
            }
 
        }

        public void respcmptxt(string exTxt)
        {
            if (deviceId == ID_CARD_READER)
            {
                string tmpStr = pCardReader.getResp();
                if (tmpStr.CompareTo(exTxt) != 0)
                {
                    throw new ScriptException(1, 1, 1, ""); 
                }
                
            }
        }

        public void statuscmptxt(string sw)
        {
            if (deviceId == ID_CARD_READER)
            {
                string tmpSw = pCardReader.getSw1Sw2();
                if (tmpSw.CompareTo(sw) != 0)
                {
                    throw new ScriptException(getStationId(), 1, 1, "命令:" + m_LastApdu + ",期望值:"+ sw +";实际值:" + tmpSw);
                }
            }
        }

        public void reset()
        {
	        if(0 != pCardReader.cardReset()) {
                Thread.Sleep(500);
                if (0 != pCardReader.cardReset())
                {
                    m_Log.setTransmitApdu("reset", "err: reset fail!");
                    throw new ScriptException(getStationId(), 1, 0, ":err: reset fail!");
                }
	        }
            m_Log.setTransmitApdu("reset", pCardReader.getResp());

        }

        public void setreader(int id)
        {
            deviceId = id;

            if (id == ID_CARD_READER)
            {
                if (pCardReader.getReaderStatus() != 0)
                {
                    int result = pCardReader.openReader();

                    if (0 != result)
                    {
                        throw new ScriptException(getStationId(), 2, result, "err: setreader()");
                    }
                }
            }
        }

        public string _getresp()
        {
            return pCardReader.getResp();
        }

        public string _getstatus()
        {
            return pCardReader.getSw1Sw2();
        }

        public int getReaderStatus()
        {
            return pCardReader.getReaderStatus();
        }

        public void beepreader()
        {
            pCardReader.readerBeep();
        }
    }

    public class ScriptException : ApplicationException
    {
	    protected int m_readerId;
	    protected int m_errSourse;
	    protected int m_errId;
	    protected string m_log; 

        public ScriptException(int readerId, int errSourse, int errId, string log = "") {
            m_readerId = readerId;
            m_errSourse = errSourse;
            m_errId = errId;
            m_log = log;
	    }
        public void printErrLog()
        {
            FileStream fs = new FileStream("./errLog.txt", FileMode.Create | FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(fs);
            //开始写入
            sw.Write(m_log + "\n");
            //清空缓冲区
            sw.Flush();
            //关闭流
            sw.Close();
            fs.Close();
            MessageBox.Show(m_log);
        }

        public string getLog()
        {
            return m_log;
        }
    }

    public class Script : MyCommand
    {
        public D6Reader m_pReader_d6_cpu;
        public D8ReaderTL m_pReader_d8_TL;

        public Script()
        {
            m_pReader_d6_cpu = null;
            m_pReader_d8_TL = null;
        }

        public string getAtrs()
        {
            setreader(2);
            reset();
            statuscmptxt("9000");
            return _getresp();
        }

        public string[] getInfo()
        {
            string []str = new string [13];
            setreader(2);
            autogetresp(1);
            
            reset();
            statuscmptxt("9000");

            sendcmd("00A404000F7378312E73682EC9E7BBE1B1A3D5CF");
            statuscmptxt("9000");

            sendcmd("00A4000002EF05");
            statuscmptxt("9000");

            sendcmd("00b2010012");
            statuscmptxt("9000");
            str[0] = _getresp().Substring(4);

            sendcmd("00b2020003");
            statuscmptxt("9000");
            str[1] = _getresp().Substring(4);

            sendcmd("00b2030006");
            statuscmptxt("9000");
            str[2] = _getresp().Substring(4);

            sendcmd("00b204000E");
            statuscmptxt("9000");
            str[3] = _getresp().Substring(4);

            sendcmd("00b2050006");
            statuscmptxt("9000");
            str[4] = _getresp().Substring(4);

            sendcmd("00b2060006");
            statuscmptxt("9000");
            str[5] = _getresp().Substring(4);

            sendcmd("00b207000B");
            statuscmptxt("9000");
            str[6] = _getresp().Substring(4);

            sendcmd("00A4000002EF06");
            statuscmptxt("9000");

            sendcmd("00b2080014");
            statuscmptxt("9000");
            str[7] = _getresp().Substring(4);

            sendcmd("00b2090020");
            statuscmptxt("9000");
            str[8] = _getresp().Substring(4);

            sendcmd("00b20A0003");
            statuscmptxt("9000");
            str[9] = _getresp().Substring(4);

            sendcmd("00b20B0003");
            statuscmptxt("9000");
            str[10] = _getresp().Substring(4);

            sendcmd("00b20C0005");
            statuscmptxt("9000");
            str[11] = _getresp().Substring(4);

            sendcmd("00b20D0006");
            statuscmptxt("9000");
            str[12] = _getresp().Substring(4);

            return str;
        }

        public string getPan()
        {
            string pan = "" ;

            setreader(2);
            ////---------切换读卡器到用户卡-------------
            //setreader 2
            setreader(2);
            //autogetresp 1
            autogetresp(1);
            //reset
            reset();
            //statuscmptxt 9000
            statuscmptxt("9000");

            sendcmd("00A404000E315041592E5359532E4444463031");
            statuscmptxt("9000");

            sendcmd("00b2010c00");

            string tmplen = _getstatus().Substring(2, 2);

            //00b2010c1D
            sendcmd("00b2010c" + tmplen);
            statuscmptxt("9000");
            //701B61194F08 A00000033301 0101500A50424F43204445424954870101 9000
            //%resp = @getresp()
            string resp = _getresp();

            string aid = _memcpy(resp, "06", "06");

            sendcmd("00A4040006" + aid);
            statuscmptxt("9000");

            //循环读0001的文件
	        int i = 1;
	        while(true)
	        {
		        string cmd = string.Format("00b2{0:X2}0C00",i);
		        sendcmd(cmd);

		        string state  = _getstatus();
                if (state.Substring(0,2) == "6C")
                {
                    sendcmd(cmd.Substring(0, 8) + state.Substring(2,2));
                    state = _getstatus();
                }
               

		        if (state == "9000")
		        {
			        resp = _getresp();
		
                    pan = "";
                    int loc = resp.IndexOf("5A0A");
                    if (loc > 0)
                    {
                        pan = resp.Substring(loc +4,19);
                        return pan;
                    }

                    int loc2 = resp.IndexOf("5A08");
                    if (loc2 > 0)
                    {
                        pan = resp.Substring(loc + 4, 16);
                        return pan;
                    }

			
			        if (pan == "")
			        {
				        i++;
				        continue;
			        }else{
				        break;
			        }
			
		        }else{
			        break;
		        }
		
	        }

            i = 1;
	        ////循环读0002的文件
	        while(true)
	        {
		        string cmd;

		        //cmd.Format("00b2%02X1400",i);
                cmd = string.Format("00b2{0:X2}1400", i);
		        sendcmd(cmd);
		
		        string state  = _getstatus();
                if (state.Substring(0, 2) == "6C")
                {
                    sendcmd(cmd.Substring(0, 8) + state.Substring(2, 2));
                    state = _getstatus();
                }
		
		        if (state == "9000")
		        {
			        resp = _getresp();

                    pan = "";
                    int loc = resp.IndexOf("5A0A");
                    if (loc > 0)
                    {
                        pan = resp.Substring(loc + 4, 19);
                        return pan;
                    }

                    int loc2 = resp.IndexOf("5A08");
                    if (loc2 > 0)
                    {
                        pan = resp.Substring(loc + 4, 16);
                        return pan;
                    }
			        if (pan == "")
			        {
				        i++;
				        continue;
			        }
			        else{
				        break;
			        }
			
		        }else{
			        break;
		        }
	        }

            i = 1;
            ////循环读0003的文件
            while (true)
            {
                string cmd;

                //cmd.Format("00b2%02X1400",i);
                cmd = string.Format("00b2{0:X2}1400", i);
                sendcmd(cmd);

                string state = _getstatus();
                if (state.Substring(0, 2) == "6C")
                {
                    sendcmd(cmd.Substring(0, 8) + state.Substring(2, 2));
                    state = _getstatus();
                }

                if (state == "9000")
                {
                    resp = _getresp();

                    pan = "";
                    int loc = resp.IndexOf("5A0A");
                    if (loc > 0)
                    {
                        pan = resp.Substring(loc + 4, 19);
                        return pan;
                    }

                    int loc2 = resp.IndexOf("5A08");
                    if (loc2 > 0)
                    {
                        pan = resp.Substring(loc + 4, 16);
                        return pan;
                    }
                    if (pan == "")
                    {
                        i++;
                        continue;
                    }
                    else
                    {
                        break;
                    }

                }
                else
                {
                    break;
                }
            }
            return pan;
        }

        public string checkSuZhouSmk()
        {
            try
            {
                string retInfo;
                string bh = "";

                reset();
                statuscmptxt("9000");
                sendcmd("00A40000023F00");
                statuscmptxt("9000");
                sendcmd("00A40000020005");
                statuscmptxt("9000");
                sendcmd("00B0000000");
                statuscmptxt("9000");
                string str_0005 = "MF_0005:"+ _getresp();
                

                sendcmd("00A4000002DF01");
                statuscmptxt("9000");

                sendcmd("00A40000020015");
                statuscmptxt("9000");
                sendcmd("00B0000000");
                statuscmptxt("9000");
                bh = _getresp().Substring(0,16);
                retInfo = bh + ",";

                string df01_0015 = "df01_0015:" + _getresp();


                sendcmd("00A40000020016");
                statuscmptxt("9000");
                sendcmd("00B0000000");
                statuscmptxt("9000");
                string df01_0016 = "df01_0016:" + _getresp();


                sendcmd("00A4000002DF03");
                statuscmptxt("9000");

                sendcmd("00A40000020015");
                statuscmptxt("9000");
                sendcmd("00B0000000");
                statuscmptxt("9000");
                string df03_0015 = "df03_0015:" + _getresp();

                sendcmd("00A40000020016");
                statuscmptxt("9000");
                sendcmd("00B0000000");
                statuscmptxt("9000");
                string df03_0016 = "df03_0016:" + _getresp();

                sendcmd("00A4000002DF04");
                statuscmptxt("9000");
                sendcmd("00A40000020003");
                statuscmptxt("9000");
                sendcmd("00B0000000");
                statuscmptxt("9000");
                string df04_0003 = "df04_0003:" + _getresp();

                reset();
                statuscmptxt("9000");
                sendcmd("00A40000023F00");
                statuscmptxt("9000");
                sendcmd("00A40000023001");
                statuscmptxt("9000");

                sendcmd("00A40000020001");
                statuscmptxt("9000");

                sendcmd("00B2030400");
                statuscmptxt("9000");

                string rsp = _getresp();
                if (rsp != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
                {
                    throw new Exception("检测失败!");
                }
                retInfo += str_0005 + ",";
                retInfo += df01_0015 + ",";
                retInfo += df01_0016 + ",";
                retInfo += df03_0015 + ",";
                retInfo += df03_0016 + ",";
                retInfo += df04_0003 + ",";

                return retInfo;
            }
            catch (ScriptException ex)
            {
                throw new Exception(ex.getLog()); ;
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
    

        }

        public void test()
        {
            setreader(2);
            reset();
            statuscmptxt("9000");
            string atr = _getresp();
            sendcmd("00A404000C57532E5359532E4444463031");
            statuscmptxt("9000");
            string str = _getresp();
  
        }
    }

    public class CardDataLog
    {
        public	CardDataLog(int stationId) {
		    m_StationId = stationId;
		    m_Mode = 0;
		    m_IsFollowPrint = false;
            fs = null;
	    }

        ~CardDataLog()
        {
            if (fs != null)
            {
                //sw.Close();
                fs.Close();
            }
        }
 
        public void setMode(int mode) {
		    m_Mode = mode;
	    }

	    public void setFollowPrint(bool tag) {
		    m_IsFollowPrint = tag;
	    }

        public string getLog()
        {
		    return m_ApduLog;
	    }

        public void closeLogFile()
        {
            if (fs != null)
            {
                //sw.Close();
                fs.Close();
                m_IsFollowPrint = false;
            }
	    }

        public void printLog()
        {
            if (fs == null)
            {
                string date = DateTime.Now.ToLongDateString().ToString();
                fs = new FileStream(@".\" + date + "_log.txt", FileMode.OpenOrCreate | FileMode.Append);
                sw = new StreamWriter(fs);
                
                sw.Write("\n" + DateTime.Now.ToLocalTime().ToString() + ":开始\n");
            }

            sw.Write(DateTime.Now.ToLocalTime().ToString() + ":" + m_ApduLog + "\n");
            sw.Flush();

        }
        public void setTransmitApdu(string cmd,string resp)
        {
            m_ApduLog = cmd + "=" + resp;
            printLog();
        }

        protected int  m_StationId;
	    protected string m_ApduLog;
	    protected string m_ExpResp;
	    protected int m_Mode;
	    protected bool m_IsFollowPrint;

        protected FileStream fs;
        protected StreamWriter sw;
    }

    public class CardDllInterface : Function
    {
        public Form1 form;
        public D6Reader m_pReader_d6_cpu;
        public D8ReaderTL m_pReader_d8_TL;
        public PCSCRead m_psscReader;

        public CardReaderInterface pCardReader;
        
        //初始化读卡器
        public string[] initReadCard()
        {
            ArrayList aList = new ArrayList(); ;
            m_pReader_d6_cpu = new D6Reader();
            m_pReader_d8_TL = new D8ReaderTL();
            m_psscReader = new PCSCRead();

            if (0 == m_pReader_d6_cpu.openReader())
            {
                aList.Add("D6");
                m_pReader_d8_TL.setPort(101);
            }

            if (0 == m_pReader_d8_TL.openReader())
            {
                aList.Add("D8");
            }
            m_psscReader.iniDevice();
            foreach (string s in m_psscReader.m_readerList)
            {
                aList.Add(s);
            }

            return (string[])aList.ToArray(typeof(string));
        }

        public void setReader(string readname)
        {
            if (readname == "D6") {
                pCardReader = m_pReader_d6_cpu;
            } else if (readname == "D8") {
                pCardReader = m_pReader_d8_TL;
            } else {
                m_psscReader.ReaderName = readname;
                pCardReader = m_psscReader;
                pCardReader.openReader();
            }
        }

        public string reset()
        {
            string atr = "";
            int ret = pCardReader.cardReset();
            atr = pCardReader.getResp();
            return atr;
        }

        public string sendcmd(string apdu)
        {
            pCardReader.sendApdu(apdu);
            
            return pCardReader.getResp() + pCardReader.getSw1Sw2();
        }

        [DllImport("JsScriptRun.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "CtdMakeCardBegin", SetLastError = false)]
        private static extern void CtdMakeCardBegin(CardCommandTypeDelegate send, CardCommandTypeDelegate reset,
            LockOrUnLockType lock1, LockOrUnLockType lock2);

        [DllImport("JsScriptRun.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "CtdMakeCard", SetLastError = false)]
        private static extern bool CtdMakeCard(int sChannelID, ref UInt32 len, [MarshalAs(UnmanagedType.LPArray, SizeConst = 600)]byte[] buffer, int iNum);
        public delegate int LockOrUnLockType();
        public static LockOrUnLockType lockF;
        private int LockOrUnLockTypeF()
        {
            return 1;
        }

        private int dllsendcmd(IntPtr reader, ref UInt32 len, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 300)]byte[] buffer)
        {
            string apdu = ByteToHexStr(buffer,(int)len);
            long ret = pCardReader.sendApdu(apdu);
            string rsp = pCardReader.getResp() + pCardReader.getSw1Sw2();
            form.printApdu(apdu + "=" + rsp);

            byte[] rspByte = HexStrToByte(rsp);
            Array.Copy(rspByte, buffer, rsp.Length / 2);
            len = (UInt32)rsp.Length / 2;
            return (int)ret;
        }

        private int dllreset(IntPtr reader, ref UInt32 len, [In,Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 300)]byte[] buffer)
        {
            int ret = pCardReader.cardReset();
            string atr = pCardReader.getResp();
            form.printApdu("reset" + "=" + atr);

            byte[] bufatr = Function.strToToHexByte(atr);
            Array.Copy(bufatr, buffer, atr.Length / 2);
            len = (UInt32) (atr.Length / 2);
            return ret;
        }

        public delegate int CardCommandTypeDelegate(IntPtr reader, ref UInt32 len,
            [In,Out,MarshalAs(UnmanagedType.LPArray, SizeConst = 300)]byte[] buffer);

        public static CardCommandTypeDelegate g_commd;
        public static CardCommandTypeDelegate g_reset;
        private void test()
        {
            g_commd = dllsendcmd;
            g_reset = dllreset;
            lockF = LockOrUnLockTypeF;
            CtdMakeCardBegin(g_commd, g_reset, lockF, lockF);

            string cmd = "E7FB56F809";
            byte[] buf = Function.strToToHexByte(cmd);
            UInt32 len = (UInt32)cmd.Length / 2;
            CtdMakeCard(1, ref len,buf,1);
        }

        [DllImport("JsScriptRun.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi
             , EntryPoint = "CtdRunJsScript", SetLastError = false)]
        private static extern bool CtdRunJsScript(int sChannelID, [MarshalAs(UnmanagedType.LPArray, SizeConst = 600)]byte[] buffer, int iNum);

        public bool runJs(string path)
        {
            try
            {
                g_commd = dllsendcmd;
                g_reset = dllreset;
                lockF = LockOrUnLockTypeF;
                CtdMakeCardBegin(g_commd, g_reset, lockF, lockF);

                byte[] pathbuf = System.Text.Encoding.Default.GetBytes(path);
                byte[] buf = new byte[600];
                Array.Copy(pathbuf, buf, pathbuf.Length);
                UInt32 len = (UInt32)buf.Length;
                return CtdRunJsScript(1, buf, 1);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }
    }
}
